/*
 * @(#)OrderServiceImpl.java 2021年3月8日
 *
 * Copyright (c) 2010 by rayootech.com. All rights reserved.
 */
package com.nuctech.order.service.impl;

import java.util.Date;

import com.alibaba.fastjson.JSON;
import com.nuctech.common.entity.Product;
import com.nuctech.order.service.ProductService;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.nuctech.common.entity.Order;
import com.nuctech.common.entity.TxLog;
import com.nuctech.order.dao.OrderDao;
import com.nuctech.order.dao.TxLogDao;
import com.nuctech.order.service.OrderService;

import cn.hutool.core.util.IdUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 订单业务接口实现类
 *
 * @author lilu
 * @date 2021年3月8日
 * @since 1.0.0
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

	@Autowired
	private OrderDao orderDao;

	@Autowired
	private TxLogDao txLogDao;

	@Autowired
	private ProductService productService;

	@Autowired
	private RocketMQTemplate rocketMQTemplate;

	@Override
	public Order get(Integer oid) {
		return this.orderDao.findById(oid).get();
	}

	@Override
	public void createOrder(Order order) {
		this.orderDao.save(order);
	}

	@Override
	public void createOrderBefore(Order order) {
		String txId = IdUtil.fastSimpleUUID(); // 事务编号
		String topic = "test-tx-topic-1:tag";  // 带标签的主题
		this.rocketMQTemplate.sendMessageInTransaction(topic,
				MessageBuilder.withPayload(order).setHeader(RocketMQHeaders.TRANSACTION_ID, txId).build(), order);
	}

	@Override
	@Transactional
	public void createOrderTx(Order order, String txId) {
		// 保存订单
		this.orderDao.save(order);
		// 记录事务日志
		this.txLogDao.save(new TxLog().setTxId(txId).setDate(new Date()));
	}

	@Override
	// 分布式事务的入口标注 @GlobalTransactional 注解，并且每个事务加上 @Transactional 注解
	@GlobalTransactional(rollbackFor = {Exception.class, RuntimeException.class}, timeoutMills = 300000)
	public Order createOrderDT(Integer pid) {
		log.info("接收到{}号商品的下单请求，接下来调用商品微服务查询此商品信息。", pid);
		// 1、调用微服务查询商品信息
		Product product = this.productService.product(pid);
		if (product.getPid() < 0) {
			return new Order().setOid(-1).setPname("下单失败");
		}
		log.info("查询到{}号商品信息，内容是：{}", pid, JSON.toJSONString(product));

		// 2、下单
		Order order = new Order()
			.setUid(1)
			.setUsername("测试用户")
			.setPid(product.getPid())
			.setPname(product.getPname())
			.setPprice(product.getPprice())
			.setNumber(1);

		this.orderDao.save(order);
		log.info("创建订单成功，订单信息为：{}", JSON.toJSONString(order));

		// 3、减扣库存
		this.productService.reduceInventery(pid, order.getNumber());

		// 4、向MQ中投递一个下单成功的消息
		this.rocketMQTemplate.convertAndSend("order-topic", order);

		return order;
	}

	@Override
	@SentinelResource(
		value = "message",
		blockHandler = "blockHandler",
		fallback = "fallback"
	) // 定义Sentinel资源
	public String message(String name) {
		return "message";
	}

	// blockHandler
	public String blockHandler(String name, BlockException e) {
		log.error("触发了BlockException异常，异常信息为：{}", e);
		return "BlockException";
	}

	// fallback【生产项目为了方便只用这个就可以】
	public String fallback(String name, Throwable e) {
		log.error("触发了Throwable异常，异常信息为：{}", e);
		return "Throwable";
	}

}
